﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;

namespace SharePoint.SPSilver
{
    class Field
    {
        private SPField f;
        private List<ClassIngredients> classList;
        public Field(SPField _f, List<ClassIngredients> _classList)
        {
            // TODO: Complete member initialization
            this.f = _f;
            this.classList = _classList;
        }
        public string Description { get { return f.Description; } }

        public String TypeAsString { get { return f.TypeAsString; } }

        public Guid Id { get { return f.Id; } }

        public Boolean Indexed { get { return f.Indexed; } }

        public string InternalName { get { return f.InternalName; } }

        public string DisplayName { get { return f.Title; } }

        public SPFieldType Type { get { return f.Type; } }

        /// <summary>
        /// constructs the safeXXX() function
        /// </summary>
        /// <param name="type">is the SharePoint Type Name, they do not coincide with C# types</param>
        /// <param name="fieldName">the internal name of the field</param>
        /// <param name="extraSafeChecking">if true an extra check is added to make sure the field is populated before the casting. This check is resource consuming!</param>
        /// <returns>function call like this: safeBoolean(i[Fields.hotTopic]);</returns>
        public String safeCasting()// , Boolean extraSafeChecking)
        {
            string type = this.cSharpType();
            string fieldName = f.InternalName;
            switch (type)
            {
                   
                // case SPFieldType.Currency ???
                case "MultimediaUpload":
                    return String.Format("safe<String>(i, Fields.{0})", fieldName);

                case "TaxonomyFieldType":
                    return String.Format(" safe<TaxonomyFieldValue>(i, Fields.{0})", fieldName);

                case "TaxonomyFieldTypeMulti":
                    return String.Format(" safe<TaxonomyFieldValueCollection>(i, Fields.{0})", fieldName);

                case "HTML":
                    return String.Format("new HTML(safe<String>(i, Fields.{0}))", fieldName);

                case "videoIDs":
                    return String.Format("new videoIDs(safe<String>(i, Fields.{0}))", fieldName);

                case "Calculated":
                    return String.Format("new Object(safe<String>(i, Fields.{0}))", fieldName);

                case "String":
                case "Boolean":
                case "Int32":
                case "DateTime":
                case "String /* SPFieldChoice */ ":
                case "String /* SPFieldMultiChoice */ ":
                    return String.Format("safe<{1}>(i, Fields.{0})", fieldName, type);

                default:
                case "Object":
                    String listClassName = String.Empty;
                    // foreach (var newClass in classList)
                    if (f is SPFieldLookup)
                    {
                        // if (newClass.contentTypeName == f.InternalName)
                        Guid listGuid = new Guid(((SPFieldLookup)f).LookupList);
                        if (classList.Exists(l => l.list.ID==listGuid))
                        {
                            ClassIngredients thisClassIngredients = 
                                        this.classList.First(p => p.list.ID == listGuid);// p => p.list.RootFolder.Url == f.ParentList.RootFolder.Url);

                            listClassName = thisClassIngredients.list.RootFolder.Name;
                            listClassName = listClassName.Replace(" ", ""); //.Replace(" ", "") //any other invalid characters?

                            if ((f as SPFieldLookup).AllowMultipleValues)
                            {
                                return String.Format("(new {1}(i.Web)).getByIds(safe<SPFieldLookupValueCollection>(i,Fields.{0}));",
                                f.InternalName,
                                listClassName/*
                                thisClassIngredients.contentTypeName*/);
                            }
                            else
                                return String.Format("(new {1}(i.Web)).getById(safe<SPFieldLookupValue>(i,Fields.{0}).LookupId);",
                                f.InternalName,
                                listClassName/*
                                thisClassIngredients.contentTypeName*/);
                        }
                    }
                    return String.Format("safe<{1}>(i, Fields.{0})", fieldName, type);
            }
        }



        /// <summary>
        /// returns the C# corresponding type as String
        /// </summary>
        /// <param name="fieldType">The SPFieldType</param>
        /// <returns></returns>
        public string cSharpType()
        {

            {
                String returnValue = "";
                switch (this.Type)
                {
                    case SPFieldType.Boolean:
                        returnValue = "Boolean";
                        break;
                    case SPFieldType.Note:
                    case SPFieldType.Text:
                        returnValue = "String";
                        break;
                    case SPFieldType.Number:
                        returnValue = "Int32";
                        break;
                    case SPFieldType.DateTime:
                        returnValue = "DateTime";
                        break;
                    case SPFieldType.Lookup:
                        // if (field.
                        // foreach (var newClass in classList)
                        {
                            // if (newClass.contentTypeName == f.InternalName)
                            Guid listGuid = new Guid(((SPFieldLookup)f).LookupList);
                            if (classList.Exists(l => l.list.ID==listGuid))
                            {
                                ClassIngredients thisClassIngredients = 
                                        this.classList.First(p => p.list.ID == listGuid);
                                return ((f as SPFieldLookup).AllowMultipleValues)?
                                    "List<"+thisClassIngredients.contentTypeName +">":
                                    thisClassIngredients.contentTypeName /* +  f.InternalName*/;
                            }
                        }
                        if ((f as SPFieldLookup).AllowMultipleValues)
                            returnValue = "SPFieldLookupValueCollection";
                        else
                            returnValue = "SPFieldLookupValue";
                        break;
                    case SPFieldType.Choice:
                        if (f is SPFieldMultiChoice)
                        {
                            if ((f as SPFieldMultiChoice).FieldRenderingControl.ToString() == "Microsoft.SharePoint.WebControls.RadioButtonChoiceField")
                                returnValue = "String /* SPFieldChoice */ ";
                            else
                                returnValue = "String /* SPFieldMultiChoice */ ";
                        }
                        else
                            returnValue = "String /* SPFieldChoice */ ";

                        break;
                    default:
                        returnValue = f.TypeAsString;
                        switch (returnValue)
                        {
                            case "MultimediaUpload":
                                returnValue = "String";
                                break;
                            case "TaxonomyFieldType":
                                returnValue = "TaxonomyFieldValue";
                                break;
                            case "TaxonomyFieldTypeMulti":
                                returnValue = "TaxonomyFieldValueCollection";
                                break;
                            case "Calculated":
                                returnValue = "Object";
                                break;
                            case "HTML":
                                returnValue = "HTML";
                                break;
                            default:
                                if (f.FieldValueType != null)
                                    returnValue = f.FieldValueType.ToString();
                                else
                                    returnValue = f.GetType().ToString();
                                break;
                        }
                        break;
                }
                return returnValue;
                /*    
                    // Summary:
                    //     Not used. Value = 0.
                    Invalid = 0,
                    //
                    // Summary:
                    //     Specifies positive or negative integer values. Corresponds to the Integer
                    //     field type that is specified on the Field element. Value = 1.
                    Integer = 1,
                    //
                    // Summary:
                    //     Specifies a single line of text. Corresponds to the Microsoft.SharePoint.SPFieldText
                    //     class and to the Text field type that is specified on the Field element.
                    //     Value = 2.
                    Text = 2,
                    //
                    // Summary:
                    //     Specifies a field that can contain multiple lines of text. Corresponds to
                    //     the Microsoft.SharePoint.SPFieldMultiLineText class and to the Note field
                    //     type that is specified on the Field element. Value = 3.
                    Note = 3,
                    //
                    // Summary:
                    //     Specifies date and time values. Corresponds to the Microsoft.SharePoint.SPFieldDateTime
                    //     class and to the DateTime field type that is specified on the Field element.
                    //     Value = 4.
                    DateTime = 4,
                    //
                    // Summary:
                    //     Specifies an integer used for internal ID fields. Corresponds to the Counter
                    //     field type that is specified on the Field element. Value = 5.
                    Counter = 5,
                    //
                    // Summary:
                    //     Specifies a predetermined set of values that can be used to enter data into
                    //     the field. Corresponds to the Microsoft.SharePoint.SPFieldChoice class and
                    //     to the Choice field type that is specified on the Field element. Value =
                    //     6.
                    Choice = 6,
                    //
                    // Summary:
                    //     Specifies references to values in other lists. Corresponds to the Microsoft.SharePoint.SPFieldLookup
                    //     class and to the Lookup field type that is specified on the Field element.
                    //     Value = 7.
                    Lookup = 7,
                    //
                    // Summary:
                    //     Specifies Boolean values that are stored in the database as 1 or 0. Corresponds
                    //     to the Microsoft.SharePoint.SPFieldBoolean class and to the Boolean field
                    //     type that is specified on the Field element. Value = 8.
                    Boolean = 8,
                    //
                    // Summary:
                    //     Specifies floating point numbers. Corresponds to the Microsoft.SharePoint.SPFieldNumber
                    //     class and to the Number field type that is specified on the Field element.
                    //     Value = 9.
                    Number = 9,
                    //
                    // Summary:
                    //     Specifies currency values formatted based on a specific locale. Corresponds
                    //     to the Microsoft.SharePoint.SPFieldCurrency class and to the Currency field
                    //     type that is specified on the Field element. Value = 10.
                    Currency = 10,
                    //
                    // Summary:
                    //     Specifies hyperlinks. Corresponds to the Microsoft.SharePoint.SPFieldUrl
                    //     class and to the URL field type that is specified on the Field element. Value
                    //     = 11.
                    URL = 11,
                    //
                    // Summary:
                    //     Specifies an abstract field type that depends on other fields for its content
                    //     and definition. Corresponds to the Microsoft.SharePoint.SPFieldComputed class
                    //     and to the Computed field type that is specified on the Field element. Value
                    //     = 12.
                    Computed = 12,
                    //
                    // Summary:
                    //     Specifies a field that is used in the creation and display of threaded Web
                    //     discussions. Corresponds to the Threading field type that is specified on
                    //     the Field element. Value = 13.
                    Threading = 13,
                    //
                    // Summary:
                    //     Specifies GUIDs. Corresponds to the Guid field type that is specified on
                    //     the Field element. Value = 14.
                    Guid = 14,
                    //
                    // Summary:
                    //     Specifies multiple values per list item. Corresponds to the Microsoft.SharePoint.SPFieldMultiChoice
                    //     class and to the MultiChoice field type that is specified on the Field element.
                    //     Value = 15.
                    MultiChoice = 15,
                    //
                    // Summary:
                    //     Specifies a Choice field for a data sheet. Corresponds to the Microsoft.SharePoint.SPFieldRatingScale
                    //     class and to the GridChoice field type that is specified on the Field element.
                    //     Value = 16.
                    GridChoice = 16,
                    //
                    // Summary:
                    //     Specifies calculated values. Corresponds to the Microsoft.SharePoint.SPFieldCalculated
                    //     class and to the Calculated field type that is specified on the Field element.
                    //     Value = 17.
                    Calculated = 17,
                    //
                    // Summary:
                    //     Specifies files. Corresponds to the Microsoft.SharePoint.SPFieldFile class
                    //     and to the File field type that is specified on the Field element. Value
                    //     = 18.
                    File = 18,
                    //
                    // Summary:
                    //     Specifies attachments. Corresponds to the Microsoft.SharePoint.SPFieldAttachments
                    //     class and to the Attachments field type that is specified on the Field element.
                    //     Value = 19.
                    Attachments = 19,
                    //
                    // Summary:
                    //     Specifies users of a SharePoint site. Corresponds to the Microsoft.SharePoint.SPFieldUser
                    //     class and to the User field type that is specified on the Field element.
                    //     Value = 20.
                    User = 20,
                    //
                    // Summary:
                    //     Specifies a field that is used in calendars for recurring events and abstract
                    //     field type that, like computed fields, depends on other fields for its content
                    //     and definition. Corresponds to the Microsoft.SharePoint.SPFieldRecurrence
                    //     class and to the Recurrence field type that is specified on the Field element.
                    //     Value = 21.
                    Recurrence = 21,
                    //
                    // Summary:
                    //     Specifies a link between projects in a Meetings Workspace site. Corresponds
                    //     to the Microsoft.SharePoint.SPFieldCrossProjectLink class and to the CrossProjectLink
                    //     field type that is specified on the Field element. Value = 22.
                    CrossProjectLink = 22,
                    //
                    // Summary:
                    //     Specifies Content Approval status. Corresponds to the Microsoft.SharePoint.SPFieldModStat
                    //     class and to the ModStat field type that is specified on the Field element.
                    //     Value = 23.
                    ModStat = 23,
                    //
                    // Summary:
                    //     Specifies errors. Value = 24.
                    Error = 24,
                    //
                    // Summary:
                    //     Specifies a content type ID. Corresponds to the ContentTypeId field type
                    //     that is specified on the Field element. Value = 25.
                    ContentTypeId = 25,
                    //
                    // Summary:
                    //     Inserts a page break in a survey list. Corresponds to the Microsoft.SharePoint.SPFieldPageSeparator
                    //     class and to the PageSeparator field type that is specified on the Field
                    //     element. Value = 26.
                    PageSeparator = 26,
                    //
                    // Summary:
                    //     Specifies the ID that indicates the relative position of a message within
                    //     a conversation thread. Corresponds to the ThreadIndex field type that is
                    //     specified on the Field element. Value = 27.
                    ThreadIndex = 27,
                    //
                    // Summary:
                    //     Specifies workflow status. Corresponds to the Microsoft.SharePoint.SPFieldWorkflowStatus
                    //     class and to the WorkflowStatus field type that is specified on the Field
                    //     element. Value = 28.
                    WorkflowStatus = 28,
                    //
                    // Summary:
                    //     Specifies an all day event. Corresponds to the Microsoft.SharePoint.SPFieldAllDayEvent
                    //     class and to the AllDayEvent field type that is specified on the Field element.
                    //     Value = 29.
                    AllDayEvent = 29,
                    //
                    // Summary:
                    //     Specifies a workflow event type. Corresponds to the WorkflowEventType field
                    //     type that is specified on the Field element. Value = 30.
                    WorkflowEventType = 30,
                    //
                    // Summary:
                    //     Specifies the maximum number of items. Value = 31.
                    MaxItems = 31,
                 */
            }
        }

        /// <summary>
        /// This is the new name of this fields. It will be used as a property name
        /// </summary>
        public String newPropertyName { get { return InternalName; } }

        public string newPropertyType { get { return cSharpType(); } }

        public String isNew 
        { 
            get
            {
                return (
                    (InternalName == "Title")
                    || (InternalName == "Modified")
                    || (InternalName == "Created")
                    || (InternalName == "Author")
                    || (InternalName == "Editor"))
                    ?" new":String.Empty;
            } 
        }
    }
}
